//
//  ST_TianLocationComponent.swift
//  btvideo
//
//  Created by Jason on 2021/11/5.
//  Copyright © 2021 JarvanZhang. All rights reserved.
//

import Foundation
import Alamofire
import SwiftyJSON
import AMapLocationKit
import RxCocoa
import RxSwift
import RealmSwift
import CoreLocation


class ST_TianLocationComponent:NSObject{
    
    private lazy var location_manager:AMapLocationManager = {
        let manger = AMapLocationManager()
        manger.desiredAccuracy = kCLLocationAccuracyHundredMeters
        manger.locationTimeout = 2
        manger.reGeocodeTimeout = 2
        manger.delegate = self
        return manger
    }()
    
    private var isFirst = true
    
    /// api定位
    private var api_location_result:ST_LocationOptionCellModel?
    
    ///外部监听 城市改变
    let city_observer = BehaviorRelay<String?>.init(value: nil)
    
    /// 保存位置到服务器成功
    let loc_pushed_observer = BehaviorSubject<Int?>(value: nil)
    
    /// 当前位置
    var current_address:ST_LocationOptionCellModel?{
        
        guard let user = ST_BTUserInfoManager.shared.current_account_info?.userinfo else{
            return nil
        }
        
        let realm = try! Realm()
        
        let item = realm.objects(ST_LocationOptionCellModel.self).filter(NSPredicate.init(format: "accid == %@ && isSelected == true", user.accid)).first
        
        return item
        
    }
    
    
    
}

extension ST_TianLocationComponent{
    
    
    /**请求粗略定位📌*/
    private func request_inaccuracy_location()->Observable<ST_LocationOptionCellModel>{
        
        
        return TIANSession(requestUrl: PH.apiLocation).flatMap { result ->Observable<ST_LocationOptionCellModel> in
            
            
            switch result{
            case .success(let json):
                
                let swiftyJsonVar = json["data"]["result"]
                
                print("IP 定位返回数据：",swiftyJsonVar)
                
                let adcode = swiftyJsonVar["ad_info"]["adcode"].stringValue
                
                guard adcode.count > 1 else {
                    
                    print("IP 定位返回数据 error:",json)
                    
                    return Observable.error(ST_NetworkError.init(code: -1, e: "错误"))
                }
                
                
                
                let location = swiftyJsonVar["location"]
                
                let locModel = ST_LocationOptionCellModel()
                
                
                print("Tecent Map -start- ",locModel)
                
                if let latitude = location["lat"].double,let longitude = location["lng"].double{
                    
                    locModel.longitude = longitude
                    
                    locModel.latitude = latitude
                    
                }
                
                let adInfo = swiftyJsonVar["ad_info"]
                
                locModel.adcode = adcode
                
                locModel.province = adInfo["province"].stringValue
                
                locModel.city = adInfo["city"].stringValue
                
                locModel.district = adInfo["district"].stringValue
                
                print("Tecent Map -end- ",locModel)
                
                ///自己保存一次
                self.api_location_result = locModel
                
                return Observable.just(locModel)
                
            case .failure(let e):
                
                print("IP 定位返回数据 error:",e)
                
                return Observable.error(ST_NetworkError.init(code: -1, e: "错误"))

            }
            
        }.retry(maxAttempts: 3, delay: 1)
        
    }
    /// 请求精确定位📌
    private func request_accuracy_location()->Observable<ST_LocationOptionCellModel>{
        
        let single:Observable<ST_LocationOptionCellModel> = Observable.create { observer -> Disposable in
            
            self.location_manager.requestLocation(withReGeocode: true, completionBlock: { (locationR: CLLocation?, reGeocodeR: AMapLocationReGeocode?, error: Error?) in
                
                print("定位次数！！！")
                
                guard let location = locationR,let reGeocode = reGeocodeR else{
                    
                    observer.onError(ST_NetworkError.init(code: -1, e: "错误"))
                    
                    print("定位次数！！！---错误:",error)
                    
                    return
                }
                
                print("定位 成功:-",location,reGeocode,"---formattedAddress:",reGeocode.formattedAddress ?? "空")
                
                var locModel = ST_LocationOptionCellModel()
                
                if reGeocode.adcode != nil &&  reGeocode.adcode != nil && reGeocode.province != nil && reGeocode.city != nil{
                    
                    locModel.latitude = location.coordinate.latitude
                    locModel.longitude = location.coordinate.longitude
                    locModel.adcode = reGeocode.adcode
                    locModel.province = reGeocode.province
                    locModel.city = reGeocode.city
                    
                    if reGeocode.district != nil{
                        locModel.district = reGeocode.district
                    }
                    
                    if reGeocode.street != nil{
                        locModel.street = reGeocode.street
                    }
                    
                    if reGeocode.number != nil{
                        locModel.streetNumber = reGeocode.number
                    }
                    
                    if reGeocode.poiName != nil{
                        locModel.name = reGeocode.poiName
                    }
                    
                }else{
                    locModel = ST_LocationOptionCellModel.tain_default_location()
                }
                
                observer.onNext(locModel)
                observer.onCompleted()
            })
            
            return Disposables.create()
        }.retry { errors in
            return errors.enumerated().flatMap { (index, error) -> Observable<Int64> in
                
                if CLLocationManager.authorizationStatus() == .denied{
                    return Observable.error(error)
                }else if index <= 3 {
                    return Observable<Int64>.timer(RxTimeInterval.seconds(1), scheduler: MainScheduler.instance)
                } else {
                    return Observable.error(error)
                }
            }
        }
        
        return single
    }
    
    fileprivate func update_realm_location(loc:ST_LocationOptionCellModel){
        
        guard let user = ST_BTUserInfoManager.shared.current_account_info?.userinfo else{
            return
        }
        
        let realm = try! Realm()
        
        //        删除旧的位置  保存新的位置
        let old = realm.objects(ST_LocationOptionCellModel.self).filter(NSPredicate.init(format: "accid == %@", user.accid)).first
        
        
        if let oldModel = old{
            try! realm.write({
                realm.delete(oldModel)
            })
        }
        
        
        //        有选中状态吗？ 没有当前位置作为选中状态
        let existIsSelected = realm.objects(ST_LocationOptionCellModel.self).contains(where: ({ $0.isSelected == true && $0.accid == user.accid }))
        
        loc.accid = user.accid
        
        if !existIsSelected {
            loc.isSelected = true
        }
        
        try! realm.write({
            realm.add(loc)
        })
        
    }
    
}

extension ST_TianLocationComponent{
    
    /// 注册请求定位
    func start_register_step_locate(){
        
        SCComponets.config_component.boot_config_observer.filter{ $0 == .finished }.flatMapLatest { _ in self.request_inaccuracy_location() }.subscribe { model in
            
            var city = model.city
            
            city.removeFirst { (c) -> Bool in
                return c == "市"
            }
            self.city_observer.accept(city)
            
        } onError: { _ in
            
            self.city_observer.accept("附近")
            
        }.disposed(by: rx.disposeBag)
        
    }
    
    /// 注册location统计
    func push_location_of_registration_statistics(){
        
        guard let loc = self.api_location_result else {
            return
        }
        
        var city = loc.city
        
        //        处理直辖市
        if city.count < 1 {
            city = loc.province
        }
        
        var param = [
            "code":loc.adcode,
            "is_first":isFirst,
            "province":loc.province,
            "city":city] as [String : Any]
        
        
        param.updateValue(String(format: "%.7f", loc.coordinate.longitude), forKey: "longitude")
        
        param.updateValue(String(format: "%.7f", loc.coordinate.latitude), forKey: "latitude")
        
        TIANSession(requestUrl: PH.saveLocApi, parameters: param).wrap_response_data().retry().subscribe(onNext: { _ in
            
        }).disposed(by: rx.disposeBag)
        
    }
    
    /// 定位并且保存到服务器
    func locate_with_push_to_server(){
        
        /// 首先尝试 高德定位 ，报错再尝试 IP定位
        /// 高德已不可用，直接使用IP定位吧
        ///
        self.request_inaccuracy_location().subscribe { model in
            
            self.update_realm_location(loc: model)
            self.save_loc_to_service()
            
        } onError: { _ in
            
            self.update_realm_location(loc: ST_LocationOptionCellModel.tain_default_location())
            
            self.save_loc_to_service()
            
        }.disposed(by: rx.disposeBag)
        
        
    }
    
    func save_loc_to_service(){
        
        guard let loc = self.current_address else {
            self.loc_pushed_observer.onNext(0)
            return
        }
        
        var city = loc.city
        
        //        处理直辖市
        if city.count < 1 {
            city = loc.province
        }
        
        var param = [
            "code":loc.adcode,
            "is_first":isFirst,
            "province":loc.province,
            "city":city] as [String : Any]
        
        
        param.updateValue(String(format: "%.7f", loc.coordinate.longitude), forKey: "longitude")
        
        param.updateValue(String(format: "%.7f", loc.coordinate.latitude), forKey: "latitude")
        
        TIANSession(requestUrl: PH.saveLocApi, parameters: param).wrap_response_data().retry().subscribe(onNext: { _ in
            
            self.isFirst = false
            
            self.loc_pushed_observer.onNext(1)
            
        }).disposed(by: rx.disposeBag)
        
    }
    
}


extension ST_TianLocationComponent:AMapLocationManagerDelegate{
    
    func amap_location_manager(_ manager: AMapLocationManager!, doRequireLocationAuth location_manager: CLLocationManager!) {
        
        location_manager.requestWhenInUseAuthorization()
    }
}



extension ST_LocationOptionCellModel{
    
    static func tain_default_location()->ST_LocationOptionCellModel{
        
        let locModel = ST_LocationOptionCellModel()
        
        locModel.latitude = 30.091698
        
        locModel.longitude = 103.831154
        
        locModel.adcode = "510107"
        
        locModel.province = "四川省"
        
        locModel.city = "成都市"
        
        locModel.district = "武侯区"
        
        return locModel
    }
    
}



class ST_LocationOptionCellModel: Object,NSCopying {
  
    @objc dynamic var accid = ""
  
    @objc dynamic var isSelected = false
    
    @objc dynamic var date = Date()
  
    @objc dynamic var latitude: Double = 0

    @objc dynamic var longitude: Double = 0
      
    /**区域编码*/
    @objc dynamic var adcode = ""
    
    @objc dynamic var province = ""
    
    @objc dynamic var city = ""
    
    @objc dynamic var district = ""
    
    @objc dynamic var street = ""
    
    @objc dynamic var streetNumber = ""
    /**名称
     */
    @objc dynamic var name = ""
    
    
    private(set) var addressStr:String{
        get{
            return province + city + district + street + streetNumber
        }set{
        }
    }
    
    private(set) var coordinate:CLLocationCoordinate2D{
        get{
            return CLLocationCoordinate2D.init(latitude: latitude, longitude: longitude)
        }set{
        }
    }
    
    func copy(with zone: NSZone? = nil) -> Any {
        
        let c = ST_LocationOptionCellModel()
        
        c.accid = self.accid
        c.isSelected = self.isSelected
        c.date = self.date
        c.latitude = self.latitude
        c.longitude = self.longitude
        c.adcode = self.adcode
        c.province = self.province
        c.city = self.city
        c.district = self.district
        c.street = self.street
        c.streetNumber = self.streetNumber
        c.name = self.name
        
        return c
    }
    
    convenience init(json:JSON) {
        self.init()
        
        let array = json["location"].stringValue.split(separator: ",").map({String($0)})
        
        
        if let lng = array[safe: 0]?.double(),let lat = array[safe: 1]?.double() {
            longitude = lng
            latitude = lat
        }
        
        
        if let user = ST_BTUserInfoManager.shared.current_account_info?.userinfo{
            
            accid = user.accid
        }
        
        
        if let value = json["adcode"].string,value.count > 0 {
            adcode = value
        }else{
            adcode = ""
        }
        
        if let value = json["pname"].string,value.count > 0 {
            province = value
        }else{
            province = ""
        }
        
        if let value = json["cityname"].string,value.count > 0 {
            city = value
        }else{
            city = ""
        }
        
        if let value = json["adname"].string,value.count > 0 {
            district = value
        }else{
            district = ""
        }
        
        if let value = json["address"].string,value.count > 0 {
            street = value
        }else{
            street = ""
        }
        
        if let value = json["name"].string,value.count > 0{
            name = value
        }else if street.count > 0 {
            name = street
        }else{
            name = district
        }
        
    }
    
    func encodeFrom(json:JSON) {
        
        let regeocode = json["regeocode"]["addressComponent"]
        
        if let value = regeocode["adcode"].string,value.count > 0 {
            adcode = value
        }else{
            adcode = ""
        }
        
        if let value = regeocode["province"].string,value.count > 0 {
            province = value
        }else{
            province = ""
        }
        
        if let value = regeocode["city"].string,value.count > 0 {
            city = value
        }else{
            city = ""
        }
        
        if let value = regeocode["district"].string,value.count > 0 {
            district = value
        }else{
            district = ""
        }
        
        if let value = regeocode["streetNumber"]["street"].string,value.count > 0 {
            street = value
        }else{
            street = ""
        }
        
        if let value = regeocode["streetNumber"]["number"].string,value.count > 0 {
            streetNumber = value
        }else{
            streetNumber = ""
        }
        
        if let item = json["regeocode"]["pois"].arrayValue.first,let value = item["name"].string,value.count > 0{
            name = value
        }else if street.count > 0 {
            name = street
        }else{
            name = district
        }
    }
}
